using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketServer
{
    /// <summary>
    /// Socket服务器端
    /// </summary>
    public partial class FormServer : Form
    {
        public FormServer()
        {
            InitializeComponent();
        }

        Socket skListener = null;

        Dictionary<string, Socket> dicClients = new Dictionary<string, Socket>();

        private void btnStart_Click(object sender, EventArgs e)
        {
            btnStart.Enabled = false;
            textIP.Enabled = false;
            numPort.Enabled = false;

            // 1.创建Socket对象
            // 这个Socket是用来监听的Socket
            if (skListener == null)
            {
                skListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
            //Socket skConn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // 2.绑定IP和监听端口
            if (string.IsNullOrEmpty(textIP.Text) || numPort.Value <= 0)
            {
                MessageBox.Show("请输入需要监听的IP和端口号", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(textIP.Text), (int)numPort.Value);
            skListener.Bind(endPoint);

            // 3.开始监听
            skListener.Listen(10);
            textLog.AppendText("开始监听..." + Environment.NewLine);
            labState.ForeColor = Color.Green;
            labState.Text = "监听中...";

            // 4.一旦开始监听后，如果有客户端连接，那么就要接受客户端连接
            // 这个Socket是用来与特定用户进行通信的Socket
            // 这句话会阻塞线程
            //Socket sk1 = skListener.Accept();

            Action<string> action = (string text) =>
            {
                listBoxClients.Items.Add(text);
                textLog.AppendText($"客户端【{text}】已连接" + Environment.NewLine);
            };

            Action<string, string> action2 = (string text, string msg) =>
             {
                 textLog.AppendText($"客户端【{text}】发来消息：{msg}" + Environment.NewLine);
             };

            Action<string> action3 = (string text) =>
            {
                textLog.AppendText($"客户端【{text}】断开连接" + Environment.NewLine);
            };

            Action<string> action4 = (string text) =>
            {
                listBoxClients.Items.Remove(text);
            };

            Thread tListen = new Thread(new ThreadStart(() =>
            {
                while (true)
                {
                    Socket skClient = skListener.Accept();
                    dicClients.Add(skClient.RemoteEndPoint.ToString(), skClient);
                    Invoke(action, skClient.RemoteEndPoint.ToString());

                    ThreadPool.QueueUserWorkItem(new WaitCallback(obj =>
                    {
                        Socket skObj = obj as Socket;
                        byte[] buffer = new byte[1024];
                        while (true)
                        {
                            int r = skObj.Receive(buffer);
                            if (r == 0)
                            {
                                dicClients.Remove(skObj.RemoteEndPoint.ToString());
                                Invoke(action4, skObj.RemoteEndPoint.ToString());
                                Invoke(action3, skObj.RemoteEndPoint.ToString());
                                break;
                            }
                            string msg = Encoding.UTF8.GetString(buffer, 0, r);
                            Invoke(action2, skObj.RemoteEndPoint.ToString(), msg);
                        }
                    }), skClient);
                }
            }));

            tListen.IsBackground = true;
            tListen.Start();

            // 设置一个缓冲区
            //byte[] buffer = new byte[1024];

            // 5.接收客户发来的消息
            // 返回值就是实际接收到的字节个数
            // 这个方法用来等待接收客户端发来的消息，这个方法也会阻塞线程
            //int byte_count = sk1.Receive(buffer);

            // 5.吧用户发来的数据转换为字符串输出
            //string msg = System.Text.Encoding.UTF8.GetString(buffer, 0, byte_count);
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (listBoxClients.SelectedItem != null)
            {
                Socket sk = dicClients[listBoxClients.SelectedItem.ToString()];
                if (sk != null)
                {
                    string msg = textSendMsg.Text;
                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg);
                    sk.Send(buffer);
                    textLog.AppendText($"向客户端【{listBoxClients.SelectedItem.ToString()}】发送消息：" + msg + Environment.NewLine);
                    textSendMsg.Text = "";
                }
            }
        }
    }
}
